home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-01 / pdcurs21.zip / PRIVATE.ZIP / _VSSCANF.C < prev    next >
Text File  |  1992-11-20  |  13KB  |  433 lines

  1. /*
  2.  * This module is based on vsscanf.c and input.c from emx 0.8f library
  3.  * source which is Copyright (c) 1990-1992 by Eberhard Mattes.
  4.  * Eberhard Mattes has kindly agreed to allow this module to be incorporated
  5.  * into PDCurses.
  6.  */
  7. #ifndef        NDEBUG
  8. char *rcsid__vsscanf = "$Header: c:/curses/private/RCS/_vsscanf.c%v 2.0 1992/11/15 03:24:18 MH Rel $";
  9. #endif
  10.  
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13. #include <stdarg.h>
  14. #include <string.h>
  15. #include <limits.h>
  16. #include <ctype.h>
  17.  
  18. #define TRUE 1
  19. #define FALSE 0
  20.  
  21. #define WHITE(x) ((x) == ' ' || (x) == '\t' || (x) == '\n')
  22.  
  23. #define NEXT(x) \
  24.         do { \
  25.             x = *buf++; \
  26.             if (x == '\0') \
  27.                return (count == 0 ? EOF : count); \
  28.             ++chars; \
  29.            } while (0)
  30. #define UNGETC(x) \
  31.         do { \
  32.             --buf; *buf = x; --chars; \
  33.            } while (0)
  34.  
  35. /*man-start*********************************************************************
  36.  
  37.   PDC_vsscanf()        - Internal routine to parse and format an input buffer.
  38.  
  39.   PDCurses Description:
  40.        This is a private PDCurses routine.
  41.  
  42.        Scan a series of input fields. Each field is formatted according to
  43.        a supplied format string and the formatted input is stored in the
  44.        variable number of addresses passed.
  45.  
  46.   PDCurses Return Value:
  47.        This function returns the number of input fields or EOF on error.
  48.  
  49.   PDCurses Errors:
  50.        If the supplied data is invalid or an incorrect number of arguments
  51.        are passed, EOF is returned as an error.
  52.  
  53.   Portability:
  54.        PDCurses        int PDC_vsscanf(char *buf,const char *fmt,va_list arg_ptr);
  55.  
  56. **man-end**********************************************************************/
  57.  
  58. int PDC_vsscanf ( char *buf, const char *fmt, char *arg_ptr)
  59. {
  60.   int count, chars, c, width, radix, d, i;
  61.   int *int_ptr;
  62.   long *long_ptr;
  63.   short *short_ptr;
  64.   char *char_ptr;
  65.   unsigned char f;
  66.   char neg, assign, ok, size;
  67.   unsigned long n;
  68.   char map[256], end;
  69.   double dx, dd, *dbl_ptr;
  70.   float *flt_ptr;
  71.   int exp;
  72.   char eneg;
  73.  
  74.   count = 0; chars = 0; c = 0;
  75.   while ((f = *fmt) != 0)
  76.     {
  77.       if (WHITE (f))
  78.         {
  79.           do
  80.             {
  81.               ++fmt; f = *fmt;
  82.             } while (WHITE (f));
  83.           do
  84.             {
  85.               c = *buf++;
  86.               if (c == '\0')
  87.                 {
  88.                   if (f == 0 || count != 0)
  89.                     return (count);
  90.                   else
  91.                     return (EOF);
  92.                 }
  93.               else
  94.                 ++chars;
  95.             } while (WHITE (c));
  96.           UNGETC (c);
  97.         }
  98.       else if (f != '%')
  99.         {
  100.           NEXT (c);
  101.           if (c != f)
  102.             return (count);
  103.           ++fmt;
  104.         }
  105.       else
  106.         {
  107.           assign = TRUE; width = INT_MAX;
  108.           char_ptr = NULL;
  109.           ++fmt;
  110.           if (*fmt == '*')
  111.             {
  112.               assign = FALSE;
  113.               ++fmt;
  114.             }
  115.           if (isdigit (*fmt))
  116.             {
  117.               width = 0;
  118.               while (isdigit (*fmt))
  119.                 width = width * 10 + (*fmt++ - '0');
  120.               if (width == 0) width = INT_MAX;
  121.             }
  122.           size = 0;
  123.           if (*fmt == 'h' || *fmt == 'l')
  124.             size = *fmt++;
  125.           f = *fmt;
  126.           switch (f)
  127.             {
  128.             case 'c':
  129.               if (width == INT_MAX)
  130.                 width = 1;
  131.               if (assign)
  132.                 char_ptr = va_arg (arg_ptr, char *);
  133.               while (width > 0)
  134.                 {
  135.                   --width;
  136.                   NEXT (c);
  137.                   if (assign)
  138.                     {
  139.                       *char_ptr++ = (char)c;
  140.                       ++count;
  141.                     }
  142.                 }
  143.               break;
  144.             case '[':
  145.               (void)memset (map, 0, 256);
  146.               end = 0;
  147.               ++fmt;
  148.               if (*fmt == '^')
  149.                 {
  150.                   ++fmt; end = 1;
  151.                 }
  152.               i = 0;
  153.               for (;;)
  154.                 {
  155.                   f = (unsigned char)*fmt;
  156.                   switch (f)
  157.                     {
  158.                     case 0:
  159.                       --fmt;       /* avoid skipping past 0 */
  160.                       NEXT (c);
  161.                       goto string;
  162.                     case ']':
  163.                       if (i > 0)
  164.                         {
  165.                           NEXT (c);
  166.                           goto string;
  167.                         }
  168.                       /* no break */
  169.                     default:
  170.                       if (fmt[1] == '-' && fmt[2] != 0 &&
  171.                           f < (unsigned char)fmt[2])
  172.                         {
  173.                           (void)memset (map+f, 1, (unsigned char)fmt[2]-f);
  174.                           fmt += 2;
  175.                         }
  176.                       else
  177.                         map[f] = 1;
  178.                       break;
  179.                     }
  180.                   ++fmt; ++i;
  181.                 }
  182.             case 's':
  183.               (void)memset (map, 0, 256);
  184.               map[' '] = 1;
  185.               map['\n'] = 1;
  186.               map['\t'] = 1;
  187.               end = 1;
  188.               do
  189.                 {
  190.                   NEXT (c);
  191.                 } while (WHITE (c));
  192. string:
  193.               if (assign)
  194.                 char_ptr = va_arg (arg_ptr, char *);
  195.               while (width > 0 && map[(unsigned char)c] != end)
  196.                 {
  197.                   --width;
  198.                   if (assign)
  199.                     *char_ptr++ = (char)c;
  200.                   c = *buf++;
  201.                   if (c == '\0')
  202.                     break;
  203.                   else
  204.                     ++chars;
  205.                 }
  206.               if (assign)
  207.                 {
  208.                   *char_ptr = 0;
  209.                   ++count;
  210.                 }
  211.               if (c == '\0')
  212.                 return (count);
  213.               else
  214.                 UNGETC (c);
  215.               break;
  216.             case 'f':
  217.             case 'e':
  218.             case 'E':
  219.             case 'g':
  220.             case 'G':
  221.               neg = ok = FALSE; dx = 0.0;
  222.               do
  223.                 {
  224.                   NEXT (c);
  225.                 } while (WHITE (c));
  226.               if (c == '+')
  227.                 {
  228.                   NEXT (c); --width;
  229.                 }
  230.               else if (c == '-')
  231.                 {
  232.                   neg = TRUE; NEXT (c); --width;
  233.                 }
  234.               while (width > 0 && isdigit (c))
  235.                 {
  236.                   --width;
  237.                   dx = dx * 10.0 + (double)(c - '0');
  238.                   ok = TRUE;
  239.                   c = *buf++;
  240.                   if (c == '\0')
  241.                     break;
  242.                   else
  243.                     ++chars;
  244.                 }
  245.               if (width > 0 && c == '.')
  246.                 {
  247.                   --width;
  248.                   dd = 10.0; NEXT (c);
  249.                   while (width > 0 && isdigit (c))
  250.                     {
  251.                       --width;
  252.                       dx += (double)(c - '0') / dd;
  253.                       dd *= 10.0;
  254.                       ok = TRUE;
  255.                       c = *buf++;
  256.                       if (c == '\0')
  257.                         break;
  258.                       else
  259.                         ++chars;
  260.                     }
  261.                 }
  262.               if (!ok)
  263.                 return (count);
  264.               if (width > 0 && (c == 'e' || c == 'E'))
  265.                 {
  266.                   eneg = FALSE; exp = 0; NEXT (c); --width;
  267.                   if (width > 0 && c == '+')
  268.                     {
  269.                       NEXT (c); --width;
  270.                     }
  271.                   else if (width > 0 && c == '-')
  272.                     {
  273.                       eneg = TRUE; NEXT (c); --width;
  274.                     }
  275.                   if (!(width > 0 && isdigit (c)))
  276.                     {
  277.                       UNGETC (c);
  278.                       return (count);
  279.                     }
  280.                   while (width > 0 && isdigit (c))
  281.                     {
  282.                       --width;
  283.                       exp = exp * 10 + (c - '0');
  284.                       c = *buf++;
  285.                       if (c == '\0')
  286.                         break;
  287.                       else
  288.                         ++chars;
  289.                     }
  290.                   if (eneg) exp = -exp;
  291.                   while (exp > 0)
  292.                     {
  293.                       dx *= 10.0;
  294.                       --exp;
  295.                     }
  296.                   while (exp < 0)
  297.                     {
  298.                       dx /= 10.0;
  299.                       ++exp;
  300.                     }
  301.                 }
  302.               if (assign)
  303.                 {
  304.                   if (neg) dx = -dx;
  305.                   if (size == 'l')
  306.                     {
  307.                       dbl_ptr = va_arg (arg_ptr, double *);
  308.                       *dbl_ptr = dx;
  309.                     }
  310.                   else
  311.                     {
  312.                       flt_ptr = va_arg (arg_ptr, float *);
  313.                       *flt_ptr = (float)dx;
  314.                     }
  315.                   ++count;
  316.                 }
  317.               if (c == '\0')
  318.                 return (count);
  319.               else
  320.                 UNGETC (c);
  321.               break;
  322.             case 'i':
  323.               neg = FALSE; radix = 10;
  324.               do
  325.                 {
  326.                   NEXT (c);
  327.                 } while (WHITE (c));
  328.               if (!(width > 0 && c == '0'))
  329.                 goto scan_complete_number;
  330.               NEXT (c); --width;
  331.               if (width > 0 && (c == 'x' || c == 'X'))
  332.                 {
  333.                   NEXT (c); radix = 16; --width;
  334.                 }
  335.               else if (width > 0 && (c >= '0' && c <= '7'))
  336.                 radix = 8;
  337.               goto scan_unsigned_number;
  338.             case 'd':
  339.             case 'u':
  340.             case 'o':
  341.             case 'x':
  342.             case 'X':
  343.               do
  344.                 {
  345.                   NEXT (c);
  346.                 } while (WHITE (c));
  347.               switch (f)
  348.                 {
  349.                 case 'o':           radix = 8; break;
  350.                 case 'x': case 'X': radix = 16; break;
  351.                 default:            radix = 10; break;
  352.                 }
  353. scan_complete_number:
  354.               neg = FALSE;
  355.               if (width > 0 && c == '+')
  356.                 {
  357.                   NEXT (c); --width;
  358.                 }
  359.               else if (width > 0 && c == '-' && radix == 10)
  360.                 {
  361.                   neg = TRUE; NEXT (c); --width;
  362.                 }
  363. scan_unsigned_number:
  364.               n = 0; ok = FALSE;
  365.               while (width > 0)
  366.                 {
  367.                   --width;
  368.                   if (isdigit (c))
  369.                     d = c - '0';
  370.                   else if (isupper (c))
  371.                     d = c - 'A' + 10;
  372.                   else if (islower (c))
  373.                     d = c - 'a' + 10;
  374.                   else
  375.                     break;
  376.                   if (d < 0 || d >= radix)
  377.                     break;
  378.                   ok = TRUE;
  379.                   n = n * radix + d;
  380.                   c = *buf++;
  381.                   if (c == '\0')
  382.                     break;
  383.                   else
  384.                     ++chars;
  385.                 }
  386.               if (!ok)
  387.                 return (count);
  388.               if (assign)
  389.                 {
  390.                   if (neg) n = -n;
  391.                   switch(size)
  392.                      {
  393.                       case 'h':
  394.                               short_ptr = va_arg (arg_ptr, short *);
  395.                               *short_ptr = (short)n;
  396.                               break;
  397.                       case 'l':
  398.                               long_ptr = va_arg (arg_ptr, long *);
  399.                               *long_ptr = (long)n;
  400.                               break;
  401.                       default:
  402.                               int_ptr = va_arg (arg_ptr, int *);
  403.                               *int_ptr = (int)n;
  404.                      }
  405.                   ++count;
  406.                 }
  407.               if (c == '\0')
  408.                 return (count);
  409.               else
  410.                 UNGETC (c);
  411.               break;
  412.             case 'n':
  413.               if (assign)
  414.                 {
  415.                   int_ptr = va_arg (arg_ptr, int *);
  416.                   *int_ptr = chars;
  417.                   ++count;
  418.                 }
  419.               break;
  420.             default:
  421.               if (f == 0)                 /* % at end of string */
  422.                 return (count);
  423.               NEXT (c);
  424.               if (c != f)
  425.                 return (count);
  426.               break;
  427.             }
  428.           ++fmt;
  429.         }
  430.     }
  431.   return (count);
  432. }
  433.